#include "relay.h"

static const struct mgos_config_r *r = NULL;
static const struct mgos_config_r0 *cfg_r0;
static const struct mgos_config_r1 *cfg_r1;
static const struct mgos_config_r2 *cfg_r2;
//计数器
static uint32_t counter[3] = {0};

//复制cfg
void cfg_copy(uint8_t idx, struct Relay *r_t)
{
    switch (idx)
    {
    case 0:
        cfg_r0 = mgos_sys_config_get_r0();
        r = (struct mgos_config_r *)cfg_r0;
        break;
    case 1:
        cfg_r1 = mgos_sys_config_get_r1();
        r = (struct mgos_config_r *)cfg_r1;
        break;
    case 2:
        cfg_r2 = mgos_sys_config_get_r2();
        r = (struct mgos_config_r *)cfg_r2;
        break;
    }

    //计划
    int size = strlen(r->schedule);
    //计划时间表
    if (json_scanf(r->schedule, size,
                   "{a0:%d,a1:%d,b0:%d,b1:%d,c0:%d,c1:%d,d0:%d,d1:%d,e0:%d,e1:%d,f0:%d,f1:%d}",
                   &r_t->schedule[0], &r_t->schedule[1],
                   &r_t->schedule[2], &r_t->schedule[3],
                   &r_t->schedule[4], &r_t->schedule[5],
                   &r_t->schedule[6], &r_t->schedule[7],
                   &r_t->schedule[8], &r_t->schedule[9],
                   &r_t->schedule[10], &r_t->schedule[11]) == 12)
    {
        for (uint8_t i = 0; i < 12; i += 2)
        {
            if (r_t->schedule[i + 1] > 0)
                r_t->schedule[i + 1] = r_t->schedule[i + 1] * 60 + r_t->schedule[i];
        }
    }
    else
    {
        printf("no data");
    }

    r_t->idx = r->idx;       //编号
    r_t->enable = r->enable; //标志
    r_t->pulse = r->pulse;
    r_t->t_on = r->on * 1000;
    r_t->t_duty = (r->on + r->off) * 1000;

    // free
    r = NULL;
}

//初始化
void r_init(uint8_t idx, struct Relay *r_t)
{
    cfg_copy(idx, r_t);
    r_t->state_last = false;

    //PIN
    mgos_gpio_set_mode(r_t->pin, MGOS_GPIO_MODE_OUTPUT);
    mgos_gpio_write(r_t->pin, OFF);
}

//返回秒
uint32_t get_second(int8_t tz)
{
    time_t time = (time_t)mg_time() + tz * 3600; //增加时区
    char f_time[30];
    mgos_strftime(f_time, 20, "%Y-%m-%d %H:%M:%S", (uint64_t)time);
    struct tm *t = localtime(&time);
    //uint32_t t_current = t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec;
    return t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec;
}

// Q输出
static void Q(struct Relay *r_t, bool open)
{
    if (open) //打开命令
    {
        bool pulse = r_t->pulse;
        if (r_t->t_on <= 0 || r_t->t_duty <= 0)
            pulse = false;
        if (!pulse)
        {
            mgos_gpio_write(r_t->pin, ON);
        }
        else
        {
            if (counter[r_t->idx] < r_t->t_on)
            {
                mgos_gpio_write(r_t->pin, ON);
            }
            else if (counter[r_t->idx] >= r_t->t_on && counter[r_t->idx] < r_t->t_duty)
            {
                mgos_gpio_write(r_t->pin, OFF);
            }
            else
            {
                counter[r_t->idx] = 0;
            }
            counter[r_t->idx] += TICK;
        }
    }
    else
    {
        mgos_gpio_write(r_t->pin, OFF);
    }
}

//时间检查
void r_scan(struct Relay *r_t)
{
    //取秒
    uint32_t t_current = get_second(TZ);
    if (r_t->manual)
    {
        if (t_current < r_t->manual_end && r_t->state)
        {
            Q(r_t, true);
        }
        else
        {
            Q(r_t, false);
            r_t->state = false;
            if (r_t->state_last)
            {
                // 发送已关闭
                state_update(r_t->idx, false);
                r_t->state_last = r_t->state;
            }
        }
    }
    else
    {
        //更新计划
        cfg_copy(r_t->idx, r_t);
        if (r_t->enable)
        {
            uint8_t i = 0;
            for (i = 0; i < 12; i += 2)
            {
                if (t_current >= r_t->schedule[i] && t_current < r_t->schedule[i + 1])
                {
                    Q(r_t, true);
                    r_t->state = true;
                    r_t->state_last = r_t->state;
                    break;
                }
            }

            if (i >= 12)
            {
                Q(r_t, false);
                r_t->state = false;
                if (r_t->state_last)
                {
                    // 发送已关闭
                    state_update(r_t->idx, false);
                    r_t->state_last = r_t->state;
                }
            }
            //outer
            else
            {
                Q(r_t, false);
                r_t->state = false;
            }
        }
        //
        //mg_printf_websocket_frame(c_websocket, WEBSOCKET_OP_TEXT, "{\"pin\": %d, \"state\":%d}", r_t->pin, r_t->state);
    }
}

//
void cb_myRpcManual(struct mg_rpc_request_info *ri, const char *args,
                    const char *src, void *user_data)
{
    int idx;
    bool state = false;
    struct Relay **p = (struct Relay **)user_data;

    if (json_scanf(args, strlen(args), "{idx:%d}", &idx) == 1)
    {
        struct Relay *p_relay = *(p + idx);
        json_scanf(args, strlen(args), "{duration:%d,enable:%B,pulse:%B,manual:%B,state:%B}",
                   &p_relay->duration, &p_relay->enable, &p_relay->pulse, &p_relay->manual, &p_relay->state);
        //手动结束时间
        p_relay->manual_end = get_second(TZ) + p_relay->duration * 60;
        state = p_relay->state;
        p_relay->state_last = p_relay->state;
    }

    struct mbuf fb;
    struct json_out out = JSON_OUT_MBUF(&fb);
    mbuf_init(&fb, 100);
    memset(fb.buf, 0, 100);
    json_printf(&out, "{state:%B}", state);
    mgos_rpc_send_response(ri, fb.buf);

    // free
    mbuf_free(&fb);
    p = NULL;
    // debug
    printf("\n*arg:%s\n", args);

    (void)src;
}

void ev_websocket(struct mg_connection *c, int ev, void *ev_data,
                  void *user_data)
{
    struct websocket_message *wm = (struct websocket_message *)ev_data;
    bool status = false;

    if (ev != MG_EV_WEBSOCKET_FRAME)
        return;

    printf("\nWebsocket event: [%.*s]\n\n", (int)wm->size, wm->data);

    int idx;
    struct Relay **p = (struct Relay **)user_data;

    if (json_scanf((char *)wm->data, wm->size, "{idx:%d}", &idx) == 1)
    {
        struct Relay *p_relay = *(p + idx);
        json_scanf((char *)wm->data, wm->size, "{duration:%d,enable:%B,manual:%B,state:%B}",
                   &p_relay->duration, &p_relay->enable, &p_relay->manual, &p_relay->state);
        //手动结束时间
        p_relay->manual_end = get_second(TZ) + p_relay->duration * 60;
        status = true;
    }

    p = NULL;
    mg_printf_websocket_frame(c, WEBSOCKET_OP_TEXT, "{\"status\": %d}", status);
    (void)user_data;
}

void state_update(uint8_t idx, bool state)
{
    struct mg_mgr *m = mgos_get_mgr();
    struct mg_connection *nc;

    for (nc = mg_next(m, NULL); nc != NULL; nc = mg_next(m, nc))
    {
        if (nc->flags & MG_F_IS_WEBSOCKET)
        {
            struct mbuf fb;
            struct json_out out = JSON_OUT_MBUF(&fb);
            mbuf_init(&fb, 64);
            memset(fb.buf, 0, 64);

            json_printf(&out, "{tag:%Q,idx:%d,state:%B}", "state_update", idx, state);
            mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, fb.buf, fb.len);
            mbuf_free(&fb);
            /*            mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT,
                                      "{\"tag\":%s,\"mem_f\":%d,\"date\":%s,\"t\":%2.1f,\"h\":%2.1f}",
                                      "\"info_update\"", mem_f, f_time, sht1x->t_true, sht1x->h_true); */
        }
    }

    m = NULL;
    nc = NULL;

    //(void)sht1x;
}

// init
/* void ws_init()
{
    struct mg_bind_opts bind_opts;
    // const char *err = (char *)malloc(100);

    memset(&bind_opts, 0, sizeof(bind_opts));
    //bind_opts.error_string = &err;

    c_websocket = mg_bind_opt(mgos_get_mgr(), "443", ev_websocket, NULL, bind_opts);
    if (c_websocket == NULL)
    {
        printf("\nFAIL\n\n");
        //printf("\nFAIL: %s\n\n", err);
    }
    else
    {
        mg_set_protocol_http_websocket(c_websocket);
    }
} */
